package com.ruoyi.web.controller.tool;

import com.cs.deviceManager.domain.DevDevice;
import com.cs.deviceManager.domain.DevDeviceCommand;
import com.cs.deviceManager.mqtt.ota.FirmwareUpdater;
import com.cs.deviceManager.mqtt.ota.OtaLocalCache;
import com.cs.deviceManager.mqtt.ota.OtaLocalReporter;
import com.cs.deviceManager.mqtt.ota.manager.OtaReporterManager;
import com.cs.deviceManager.service.IDevDeviceCommandService;
import com.cs.deviceManager.service.IDevDeviceService;
import com.cs.deviceManager.service.IDevLocationHistoryService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.web.controller.request.StartOtaRequest;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 设备对外接口
 *
 * @author zizige
 */
@Tag(name = "设备管理")
@RestController
@RequestMapping("/device")
public class DeviceController extends BaseController {

    @Resource
    private IDevDeviceService devDeviceService;

    @Resource
    private IDevLocationHistoryService devLocationHistoryService;

    @Resource
    private IDevDeviceCommandService devDeviceCommandService;

    @Value("${mqtt.client-id:device-status-listener}")
    private String clientId;

    static class DeviceInfo {
        private Long id;
        private Double latitude;
        private Double longitude;
        private String name;
        private String address;
        private String status;

        public DeviceInfo(Long id, Double latitude, Double longitude, String name, String address, String status) {
            this.id = id;
            this.latitude = latitude;
            this.longitude = longitude;
            this.name = name;
            this.address = address;
            this.status = status;
        }

        // Getters
        public Long getId() {
            return id;
        }

        public Double getLatitude() {
            return latitude;
        }

        public Double getLongitude() {
            return longitude;
        }

        public String getName() {
            return name;
        }

        public String getAddress() {
            return address;
        }

        public String getStatus() {
            return status;
        }
    }

    @Resource
    private OtaLocalCache otaCache;

    @Resource
    private OtaReporterManager reporterManager;

    @GetMapping("/ota/status")
    public OtaLocalCache.OtaFullStatus getStatus(@RequestParam String device_id) {
        return reporterManager.getFullStatus(device_id, otaCache);
    }


    @Resource
    private ApplicationContext applicationContext;

    @PostMapping("/ota/start")
    public R<String> startOta(@RequestBody StartOtaRequest req) {
        String deviceId = req.getDeviceId();
        String firmwareUrl = req.getFirmwareUrl();

        if (deviceId == null || firmwareUrl == null) {
            return R.fail("缺少必要参数");
        }
        System.out.println("🚀 开始 OTA 升级测试...");
        System.out.println("设备: " + deviceId);
        System.out.println("固件: " + firmwareUrl);
        new Thread(() -> {
            try {
                OtaLocalReporter reporter = new OtaLocalReporter(otaCache, deviceId);
                FirmwareUpdater updater = applicationContext.getBean(FirmwareUpdater.class);
                reporterManager.register(deviceId, reporter);
                System.out.println("🆕 创建实例: " + System.identityHashCode(updater));
                updater.setCallback(reporter);
                updater.setDeviceId(deviceId);
                updater.startUpdate(firmwareUrl);
            } catch (Exception e) {
                System.err.println("OTA 启动失败: " + e.getMessage());
            }
        }, "OTA-Thread-" + deviceId).start();

        return R.ok("OTA 任务已启动");
    }

    @Operation(summary = "获取指定经纬度附近1KM内的设备")
    @GetMapping("/nearby")
    public R<List<DeviceInfo>> getNearbyDevices(
            @Parameter(description = "纬度", required = true) @RequestParam Double latitude,
            @Parameter(description = "经度", required = true) @RequestParam Double longitude) {
        if (latitude == null || longitude == null) {
            return R.fail("纬度和经度不能为空");
        }
        List<DevDevice> devDevices = devDeviceService.selectNearbyDevices(new BigDecimal(latitude),
                new BigDecimal(longitude));
        List<DeviceInfo> deviceInfos = devDevices.stream()
                .map(device -> new DeviceInfo(
                        device.getDevId(),
                        device.getLatitude().doubleValue(),
                        device.getLongitude().doubleValue(),
                        device.getDevName(),
                        device.getCurrentLocation(),
                        device.getStatus()))
                .collect(Collectors.toList());
        return R.ok(deviceInfos);
    }

    @Operation(summary = "查询所有未绑定的设备")
    @GetMapping("/unbound")
    public R<List<DeviceInfo>> getUnboundDevices() {
        List<DevDevice> devDevices = devDeviceService.selectUnboundDevices();
        List<DeviceInfo> deviceInfos = devDevices.stream()
                .map(device -> new DeviceInfo(
                        device.getDevId(),
                        device.getLatitude() != null ? device.getLatitude().doubleValue() : null,
                        device.getLongitude() != null ? device.getLongitude().doubleValue() : null,
                        device.getDevName(),
                        device.getCurrentLocation(),
                        device.getStatus()))
                .collect(Collectors.toList());
        return R.ok(deviceInfos);
    }

    @Operation(summary = "修改设备信息")
    @PostMapping("/update")
    public R<String> updateDevice(@RequestBody DevDevice device) {
        if (device == null || device.getDevId() == null) {
            return R.fail("设备ID不能为空");
        }
        DevDevice oldDevice = devDeviceService.selectDevDeviceByDevId(device.getDevId());
        int result = devDeviceService.updateDevDevice(device);
        if (oldDevice != null && result > 0) {
            BigDecimal oldLat = oldDevice.getLatitude();
            BigDecimal oldLng = oldDevice.getLongitude();
            BigDecimal newLat = device.getLatitude();
            BigDecimal newLng = device.getLongitude();
            devLocationHistoryService.saveLocationChange(device.getDevId(), oldLat, oldLng, newLat, newLng);
        }
        return result > 0 ? R.ok("修改设备信息成功") : R.fail("修改设备信息失败");
    }

    @Operation(summary = "绑定设备经纬度")
    @PostMapping("/bind")
    public R<String> bindDevice(@RequestBody DeviceInfo dev) {
        if (dev.getId() == null || dev.getLatitude() == null || dev.getLongitude() == null) {
            return R.fail("设备ID、纬度和经度不能为空");
        }
        DevDevice oldDevice = devDeviceService.selectDevDeviceByDevId(dev.getId());
        DevDevice device = new DevDevice();
        device.setDevId(dev.getId());
        device.setLatitude(BigDecimal.valueOf(dev.getLatitude()));
        device.setLongitude(BigDecimal.valueOf(dev.getLongitude()));
        int result = devDeviceService.updateDevDevice(device);
        if (oldDevice != null && result > 0) {
            BigDecimal oldLat = oldDevice.getLatitude();
            BigDecimal oldLng = oldDevice.getLongitude();
            devLocationHistoryService.saveLocationChange(dev.getId(), oldLat, oldLng, BigDecimal.valueOf(dev.getLatitude()), BigDecimal.valueOf((dev.getLongitude())));
        }
        return result > 0 ? R.ok("绑定设备经纬度成功") : R.fail("绑定设备经纬度失败");
    }

    /**
     * 解除设备绑定
     *
     * @param devId 设备ID
     * @return 操作结果
     */
    @Operation(summary = "解除设备绑定")
    @PostMapping("/unbind")
    public R<String> unbindDevice(
            @Parameter(description = "设备ID", required = true) @RequestParam Long devId) {
        if (devId == null) {
            return R.fail("设备ID不能为空");
        }
        int result = devDeviceService.unbindDevice(devId);
        return result > 0 ? R.ok("解除绑定成功") : R.fail("解除绑定失败");
    }

    /**
     * 根据设备ID获取设备信息
     *
     * @param devId 设备ID
     * @return 设备信息
     */
    @Operation(summary = "根据设备ID获取设备信息")
    @GetMapping("/info")
    public R<DevDevice> getDeviceById(
            @Parameter(description = "设备ID", required = true) @RequestParam Long devId) {
        if (devId == null) {
            return R.fail("设备ID不能为空");
        }
        DevDevice device = devDeviceService.selectDevDeviceByDevId(devId);
        return device != null ? R.ok(device) : R.fail("未找到指定设备");
    }

    /**
     * 操作类型枚举
     */
    private enum DeviceOperationType {
        QUERY("查询"),
        FLUSH("冲洗"),
        SEND("发送"),
        RESET("恢复出厂设置");

        private final String code;

        DeviceOperationType(String code) {
            this.code = code;
        }

        public String getCode() {
            return code;
        }

        public static DeviceOperationType fromCode(String code) {
            for (DeviceOperationType type : DeviceOperationType.values()) {
                if (type.name().equals(code)) {
                    return type;
                }
            }
            throw new IllegalArgumentException("不支持的操作类型: " + code);
        }
    }

    /**
     * 设备操作接口
     *
     * @param devId 设备ID
     * @param operationType 操作类型
     * @param params 设备参数Map
     * @return 操作结果
     */
    @Operation(summary = "设备操作接口")
    @PostMapping("/operate")
    public R<String> operateDevice(
            @Parameter(description = "设备ID", required = true) @RequestParam Long devId,
            @Parameter(description = "操作类型", required = true) @RequestParam String operationType,
            @Parameter(description = "设备参数") @RequestBody(required = false) Map<String, Object> params) {
        if (devId == null || operationType == null) {
            return R.fail("设备ID和操作类型不能为空");
        }

        // 获取设备信息
        DevDevice device = devDeviceService.selectDevDeviceByDevId(devId);
        if (device == null) {
            return R.fail("未找到指定设备");
        }

        try {
            // 根据操作类型构建命令内容
            String commandContent = buildCommandContent(operationType, device, params);

            // 创建设备命令对象
            DevDeviceCommand command = new DevDeviceCommand();
            command.setDeviceId(String.valueOf(devId));
            command.setDeviceNumber(device.getDevNumber());
            command.setCommandType("OPERATION");
            command.setCommandContent(commandContent);
            command.setStatus("PENDING");
            command.setMaxRetryCount(3);
            command.setRetryCount(0);

            // 保存命令到数据库
            int result = devDeviceCommandService.insertDevDeviceCommand(command);
            if (result <= 0) {
                return R.fail("创建指令失败");
            }

            // 发送命令到设备
            boolean sendResult = devDeviceCommandService.sendCommandToDevice(command);
            if (sendResult) {
                return R.ok("操作指令已发送");
            } else {
                return R.fail("操作指令发送失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return R.fail("操作过程中发生错误: " + e.getMessage());
        }
    }

    /**
     * 根据操作类型构建命令内容
     *
     * @param operationType 操作类型
     * @param device 设备信息
     * @param params 参数Map
     * @return 命令内容
     */
    private String buildCommandContent(String operationType, DevDevice device, Map<String, Object> params) {
        DeviceOperationType type = DeviceOperationType.fromCode(operationType);

        return switch (type) {
            case QUERY -> "{\"type\":\"download\",\"properties\":{\"UP\":1}}";
            case FLUSH -> "{\"type\":\"download\",\"properties\":{\"CX\":1,\"UP\":1}}";
            case SEND ->
                // 根据前端 btSendTap 方法构建命令内容
                    buildSendCommandContent(device, params);
            case RESET -> "{\"type\":\"download\",\"properties\":{\"RESET\":1,\"UP\":1}}";
        };
    }

    /**
     * 构建发送命令内容
     *
     * @param device 设备信息
     * @param params 参数Map
     * @return 命令内容
     */
    private String buildSendCommandContent(DevDevice device, java.util.Map<String, Object> params) {
        if (params == null) {
            params = new java.util.HashMap<>();
        }
        
        // 获取设备类型
        //String devType = (String) params.getOrDefault("devType", "ISO360");
        
        // 根据设备类型确定时间参数数量
        int timePropertyCount = 8; // 默认4个

        // 构建时间属性
        StringBuilder propertiesBuilder = new StringBuilder();
        for (int i = 1; i <= timePropertyCount; i++) {
            Object timeValueObj = params.get("time" + i);
            Integer timeValue = timeValueObj instanceof Number ? ((Number) timeValueObj).intValue() : 0;
            
            // 对于索引5-8的值不乘以1000 (对应time5-time8)
            if (i >= 5) {
                propertiesBuilder.append("\"time").append(i).append("\":").append(timeValue).append(",");
            } else {
                propertiesBuilder.append("\"time").append(i).append("\":").append(timeValue * 1000).append(",");
            }
        }
        
        // 添加运行次数和UP参数
        Object runCountObj = params.get("runCount");
        Integer runCount = runCountObj instanceof Number ? ((Number) runCountObj).intValue() : 0;
        
        Object rs485IdObj = params.get("rs485Id");
        Integer rs485Id = rs485IdObj instanceof Number ? ((Number) rs485IdObj).intValue() : 0;
        
        propertiesBuilder.append("\"runcount\":").append(runCount).append(",\"UP\":1");

        // 构建完整命令
        return String.format("{\"type\":\"download\",\"device_id\":\"%s\",\"device_name\":\"%s\",\"rs485_id\":%d,\"properties\":{%s}}",
                device.getDevId(), device.getDevName(), rs485Id, propertiesBuilder);
    }
}